/**
* \file ScanBufferRing.cpp ScanBuffer Implementierung
*
*/


#include "ScanBuffer.h"
#include <iostream>
#include <fcntl.h>


#ifdef WIN32
	#define READ_CMD(fd, buf, size) _read((fd),(buf),(size))
	#define OPEN_CMD(file, option) _open((file),(option) | _O_BINARY)
	#define CLOSE_CMD(file) _close((file))
#else
	#define READ_CMD(fd, buf, size) read((fd),(buf),(size))
	#define OPEN_CMD(file, option) open((file),(option))
	#define CLOSE_CMD(file) close((file))
#endif


ScanBufferRing::ScanBufferRing(int blockSize) {
	this->blockSize = blockSize;
	this->lineCount = 0;
	this->columnCount = 1;
	this->eofCounter = -1;
	this->blockPos = 0;
	this->charPos = 0;
	this->oldColumnCount = 0;	
	
	this->buffer = new char*[2];
	this->buffer[0] = 0;
	this->buffer[1] = 0;
	
	
	this->override[0] = true;
	this->override[1] = true;
}

ScanBufferRing::~ScanBufferRing() {
	// Wenn Dateihandler g�ltig ist, Datei schlie�en. Ung�ltig zum Beispiel, wenn Datei nicht gefunden wurde
	if (this->fd != -1) CLOSE_CMD(this->fd);
	
	for (int i = 0; i < 2; i++) {
		delete[] this->buffer[i];
	}

	delete[] this->buffer;
}

/**
* @return Number of the current line.
*/
unsigned int ScanBufferRing::getLine() {
	return this->lineCount+1;
}
/**
* @return Number of the current column.
*/
unsigned int ScanBufferRing::getColumn() {
	return this->columnCount;
}

void ScanBufferRing::readBlock(int index) {
	char* tmp = new char[this->blockSize];
	int ret = READ_CMD(this->fd, tmp, this->blockSize);
	
	// delete old block only if it exists
	if(!this->buffer[index]) {
		delete[] this->buffer[index];
	}
	
	this->buffer[index] = tmp;
	
	
	if(ret < this->blockSize) {			// EOF reached
			this->eofCounter = ret;		// set global eof-counter
	}
}

char ScanBufferRing::getNextChar() {

	if(this->charPos >= this->blockSize) {
	
		if(this->blockPos == 0) {
			this->blockPos = 1;
			this->charPos = 0;
		} else if(this->blockPos == 1) {
			this->blockPos = 0;
			this->charPos = 0;
		}
		
		if(this->override[this->blockPos]) {
			this->readBlock(this->blockPos);
		} else {
			this->override[this->blockPos] = true;
			
			if(this->eofCounter >= -1) {
				this->eofCounter--;
			}
		}
	
	}
	
	this->columnCount++;
	
	if ( this->buffer[this->blockPos][this->charPos] == '\n' ) {
		this->lineCount++;
		this->oldColumnCount = this->columnCount;
		this->columnCount = 1;
	}

	//if eofCounter is set and we reached this count by getting more chars
	if(this->eofCounter >= 0 && this->eofCounter <= this->charPos) {
		// Eof auch als Zeichen z�hlen
		this->charPos++;
		throw ScanBufferIOException((char*) "End Of File!");
	}
	
	return this->buffer[this->blockPos][this->charPos++];
}

void ScanBufferRing::unGetChar() {
		
		if( this->buffer[this->blockPos][this->charPos - 1] == '\n' ) {
			this->lineCount--;
			this->columnCount = this->oldColumnCount;
		}
		
		if(this->charPos == 0) {
			if(this->blockPos == 0) {
				this->blockPos = 1;
				this->charPos = this->blockSize-1;
				this->override[1] = false;
			} else if(this->blockPos == 1) {
				this->blockPos = 0;
				this->charPos = this->blockSize-1;
				this->override[0] = false;
				
				
			}
			
			this->eofCounter++;
		} else {
			this->charPos --;
		}

		this->columnCount--;
}

void ScanBufferRing::openFile(char* filename) {		
	this->fd = OPEN_CMD(filename, O_RDONLY);

	if(this->fd == -1) {
		throw ScanBufferIOException((char*) "File not found!");
	}
	
	
	this->readBlock(0);
}

